---
title: 为什么局部变量是线程安全的
---

## 方法是如何被执行的

CPU 去哪里找调用方法的参数和返回地址，其实是通过 CPU 的堆栈寄存器。因为这个栈是和方法调用相关的，因此经常被称为调用栈。

有三个方法 A、B、C,它们的调用关系是 A -> B -> C (A 调用 B，B 调用 C)，在运行时，会构建出下面这样的栈帧。每个方法在调用栈里都会有自己的独立空间,称为**栈帧**，每个栈帧里都有对应方法需要的参数和返回地址。当调用方法时，会创建新的栈帧，并压入调用栈；当方法返回时，对应的栈帧就会被被自动弹出。也就是说，**栈帧和方法是同生共死的**。

![674bb47feccbf55cf0b6acc5c92e4fc7](https://img.wkq.pub/pic/674bb47feccbf55cf0b6acc5c92e4fc7.webp)

利用栈结构来支持方法调用这个方案非常普遍，以至于 CPU 都内置了栈寄存器。

## 局部变量存在哪里

局部变量的作用域是方法内部，也就是说当方法执行完，局部变量就没有用了，局部变量和方法应该同生共死。

调用栈的栈帧就是和方法同生共死的，所以把局部变量放到调用栈是相当的合理的。

![ece8c32d23e4777c370f594c97762a9c](https://img.wkq.pub/pic/ece8c32d23e4777c370f594c97762a9c.webp)

局部变量是和方法是同生共死的，一个方法如果想跨越方法的边界，就必须创建在堆里。

## 调用栈和线程

两个线程可以同时用不同的参数调用相同的方法，那调用栈和线程之间是什么关系呢？答案是：**每个线程都有自己独立的调用栈**。因为如果不是这样，两个线程就互相干扰了。

![840cb955e521bd51776dbcdad3dba11a](https://img.wkq.pub/pic/840cb955e521bd51776dbcdad3dba11a.webp)

因为每个线程都有自己的调用栈，局部变量保存在线程各自的调用栈里面，不会共享，所以自然就没有并发问题。

## 线程封闭

方法里的局部变量，因为不会和其它线程共享，所以没有并发问题，这个思路已经成为解决并发问题的一个重要技术。也被称为**线程封闭**。

采用线程封闭的技术的案例非常多，例如从数据库连接池里获取的连接 Connection ，在 JDBC 规范里并没有要求这个 Connection 必须是线程安全的。

数据库连接池通过线程封闭技术，保证一个 Connection 一旦被一个线程获取之后，在这个线程关闭 Connection 之前的这段时间里，不会再分配给其它线程，从而保证了 Connection 不会有并发问题。

